﻿#ifndef PLINESFIT_H
#define PLINESFIT_H

///
/// 直线拟合算法代码。包括直线拟合、平行线拟合两种。
/// 用到了 Qt 的一些功能。
///
#include <QVector>
#include <QPoint>
#include <math.h>

/**
 * @brief lineFit 最小二乘法拟合 ax + by + c = 0 型直线.
 *  参数 a 和 b 满足 a^2 + b^2 = 1。拟合的判据是点到直线的垂直距离平方和最小。不是通常意义下的一元线性回归。
 * @param points 点的坐标
 * @param [out] a 输出拟合系数
 * @param [out] b 输出拟合系数
 * @param [out] c 输出拟合系数
 * @return true 表示拟合成功，false 表示拟合失败
 */
bool lineFit(const QVector<QPointF> &line, double &a, double &b, double &c);

/**
 * @brief weightedLineFit 加权最小二乘法拟合 ax + by + c = 0 型直线。
 * 参数 a 和 b 满足 a^2 + b^2 = 1。拟合的判据是点到直线的垂直距离平方和最小。不是通常意义下的一元线性回归。
 * 权重根据点到直线的距离来确定。距离小于 tau 的权重为 1。距离大于 tau 的权重为 tau / d。 d 为点到直线距离。
 * @param line 点的坐标
 * @param [out] a 输出拟合系数
 * @param [out] b 输出拟合系数
 * @param [out] c 输出拟合系数
 * @param tau 距离小于 tau 的权重为 1。距离大于 tau 的权重为 tau / d。 d 为点到直线距离。
 * @param N 迭代次数
 * @return true 表示拟合成功，false 表示拟合失败
 */
bool weightedLineFit(const QVector<QPointF> &line, double &a, double &b, double &c, double tau, int N);



/**
* @brief plinesFit 平行线拟合算法 最小二乘法拟合 ax + by + c = 0 型直线
* @param [in] line1 第一条直线的数据点
* @param [in] line2 第二条直线的数据点
* @param [out] a 输出拟合系数
* @param [out] b 输出拟合系数
* @param [out] c1 输出拟合系数，第一条直线的方程为 ax + by + c1 = 0
* @param [out] c2 输出拟合系数，第二条直线的方程为 ax + by + c2 = 0
* @return true 表示拟合成功，false 表示拟合失败
*/
bool plinesFit(const QVector<QPointF> &line1, const QVector<QPointF> &line2,
               double &a, double &b, double &c1, double &c2);

/**
 * @brief weightedPLinesFit 加权最小二乘直线拟合。先用非加权方法估算出个直线方程，然后再迭代优化。
 * @param line1 第一条直线的数据点
 * @param line2 第二条直线的数据点
 * @param [inout] a 输出拟合系数, 同时也作为估计加权系数的依据
 * @param [inout] b 输出拟合系数, 同时也作为估计加权系数的依据
 * @param [inout] c1 输出拟合系数，第一条直线的方程为 ax + by + c1 = 0
 * @param [inout] c2 输出拟合系数，第二条直线的方程为 ax + by + c2 = 0
 * @param tau 距离小于 tau 的权重为 1。距离大于 tau 的权重为 tau / d。 d 为点到直线距离。
 * @param N 迭代次数
 * @return true 表示拟合成功，false 表示拟合失败
 */
bool weightedPLinesFit(const QVector<QPointF> &line1, const QVector<QPointF> &line2,
                      double &a, double &b, double &c1, double &c2, double tau, int N);

/**
* @brief weightedPLinesFitOneStep 加权最小二乘直线拟合。根据传进来的 a,b,c1,c2 来估计加权值。
* @param line1 第一条直线的数据点
* @param line2 第二条直线的数据点
* @param [inout] a 输出拟合系数, 同时也作为估计加权系数的依据
* @param [inout] b 输出拟合系数, 同时也作为估计加权系数的依据
* @param [inout] c1 输出拟合系数，第一条直线的方程为 ax + by + c1 = 0
* @param [inout] c2 输出拟合系数，第二条直线的方程为 ax + by + c2 = 0
* @param tau 距离小于 tau 的权重为 1。距离大于 tau 的权重为 tau / d。 d 为点到直线距离。
* @return true 表示拟合成功，false 表示拟合失败
 */
bool weightedPLinesFitOneStep(const QVector<QPointF> &line1, const QVector<QPointF> &line2,
                      double &a, double &b, double &c1, double &c2, double tau);

#endif // PLINESFIT_H
